
#include "ProgramElem.h"


#include "Type.h"


#include "SymTabMgr.h"

#include "STEClasses.h"
#include "Value.h"
#include "ParserUtil.h"

/****************************************************************/
const Type* GlobalEntry::typeCheck() 
{
	//aripio: check symtab entry
    this->symTab()->typeCheck();
    
    //william: check the rule nodes
    
    vector<RuleNode*> rules = this->rules_;
    for(vector<RuleNode*>::iterator it = rules.begin(); it != rules.end(); ++it)
    {
        RuleNode *r = *it;
        r->typeCheck();
    }
    cout<<endl;
}

void GlobalEntry::print(ostream& out, int indent)const 
{
	vector<RuleNode*>::const_iterator  iter;

	this->symTab()->printST(out,indent,' ',' ');
	out<<endl;
	for(iter = rules_.begin(); iter != rules_.end(); iter++)
	{
		(*iter)->print(out,indent);
		out<<endl;
	}
	if(rules_.empty())
		out<<endl;
	out<<endl;

}

void GlobalEntry::typePrint(ostream& out, int indent) const 
{
	/* Fill in yours */
	vector<RuleNode*>::const_iterator  iter;

	this->symTab()->typePrintST(out,indent,' ',' ');
	out<<endl;
	for(iter = rules_.begin(); iter != rules_.end(); iter++)
	{
		(*iter)->typePrint(out,indent);
		out<<endl;
	}
	if(rules_.empty())
		out<<endl;
	out<<endl;
}
/****************************************************************/
const Type* EventEntry::typeCheck() {/* Fill in yours */}
void EventEntry::print(ostream&, int indent) const {/* Fill in yours */}
void EventEntry::typePrint(ostream& os, int indent) const
{/* Fill in yours */
	//xiaohua hou
	const SymTab* temp = symTab();

	os<<"event"<<" ";
	os<<this->name();
	os<<"(";

	if(temp)
	{
		int i = 1;
		SymTab::const_iterator it = temp->begin();
		do{
			SymTabEntry *ste = (SymTabEntry *)(*it);
			ste->typePrint(os, indent);
			if(i != temp->size())
				os<<", ";
			++it;
			++i;
		}while(it != temp->end());
	}

	os<<")"<<";";
}
/****************************************************************/
const Type* ClassEntry::typeCheck() {/* Fill in yours */}

void ClassEntry::print(ostream& os, int indent)const
{
	os<<"class"<<" "<<this->name()<<";";
}

void ClassEntry::typePrint(ostream& os, int indent) const {
    //william
    os<<"class"<<" "<<this->name();

}
/****************************************************************/
VariableEntry::VariableEntry(const VariableEntry &v):SymTabEntry(v.name(),v.kind(),0,0,""){

    
}

void VariableEntry::print(ostream& os, int indent)const
{
	os<<this->type()->name()<<" ";
	if(this->type()->tag() == Type::CLASS)
		os<<this->type()->typeDesc()->name()<<" ";
	os<<this->name();
	if(initVal_ != NULL)
	{
		os<<" = ";
		initVal_->print(os,indent);
	}
	if(this->varKind() != VariableEntry::PARAM_VAR)
		cout<<";";	
}

const Type* VariableEntry::typeCheck(){
    //william
 /*   ExprNode *rhs = this->initVal_;
    Type *rhsType = (initVal_ != NULL) ? this->initVal_->type(): NULL;
    Type *lhsType = this->type();

    if (lhsType->tag() == Type::CLASS && rhsType->tag() == Type::CLASS) {
        if (lhsType->typeDesc()!=NULL && rhsType->typeDesc()!=NULL) {
            if (lhsType->typeDesc() != rhsType->typeDesc()) {
                cout<<"clas1---------"<<lhsType->typeDesc()->name()<<endl;
                cout<<"clas2---------"<<rhsType->typeDesc()->name()<<endl;
                errMsg("Error: Assignment between incompatible types");
                return new Type(Type::ERROR);
            }else
                return type();
        }
    }

    

    if (rhsType != NULL && lhsType != NULL && rhsType->typeDesc()!=NULL) {
        if (lhsType->tag() == Type::CLASS ) {
            cout<<"clas1---------"<<lhsType->typeDesc()->name()<<endl;
            cout<<"clas2---------"<<rhsType->typeDesc()->name()<<endl;
        }
    }
 
     if (rhs != NULL) {
        if (!rhs->type()->isSubType(*lhsType)) {
            errMsg("Assignment between incompatible types");
        }
        return type();
    }*/
    if(this->initVal() != NULL)
    {
    	const Type *t = this->initVal()->type();
    	
    
    if(t->tag() == Type::CLASS)
    {
    	if (this->type()->tag() != Type::CLASS || (this->type()->tag() == Type::CLASS 
        && this->type()->typeDesc()->name() != ((RefExprNode*)this->initVal())->symTabEntry()->type()->typeDesc()->name()))
    		errMsg("Assignment between incompatible types",line(),0,file().c_str());
    	
    }
    else
    	if (!t->isSubType(this->type()->tag())) 
    {
        errMsg("Assignment between incompatible types",line(),0,file().c_str());
    }
    }

}

void VariableEntry::typePrint(ostream& os, int indent) const 
{
	os<<this->type()->name()<<" ";
	if(this->type()->tag() == Type::CLASS)
		os<<this->type()->typeDesc()->name()<<" ";
	os<<this->name();
	if(initVal_ != NULL)
	{
		os<<" = ";
		initVal_->typePrint(os,indent);
	}
	if(this->varKind() != VariableEntry::PARAM_VAR)
		cout<<";";	
}
/****************************************************************/
const Type* BlockEntry::typeCheck(){}

void BlockEntry::print(ostream& out, int indent) const
{
	if(this->symTab())
	  this->symTab()->printST(out,indent);
	
}

void BlockEntry::typePrint(ostream& os, int indent) const{}
/****************************************************************/ 
const Type* FunctionEntry::typeCheck()
{
	if(this->body() != NULL)
		this->body()->typeCheck();
}


    //vector<RuleNode*> rules = this->rules_;
    //for(vector<RuleNode*>::iterator it = rules.begin(); it != rules.end(); ++it)
    /*
    vector<VariableEntry*> *args = this->formals_;
    
    for(vector<VariableEntry*>::iterator it = args.begin(); it != args.end(); it++)
    {
        VariableEntry *r = *it;
        cout<<r->type()->fullName()<<endl;
    }
     */


void FunctionEntry::print(ostream& os, int indent) const
{
	os<<this->type()->retType()->name()<<" "<<this->name();
	bool bc = false;
	if(this->body() == NULL)
	{
	if(this->symTab())
	  this->symTab()->printST(os,indent,'(',')',false);
	else 
		os<<"("<<")";
	}
	else
	{
		
		int i = 1;
		SymTab::const_iterator iter(*(this->symTab()->begin()));
		for(; iter != *(this->symTab()->end()); ++iter)
		{	if((*iter)->kind() == SymTabEntry::BLOCK_KIND)
			{
				
				break;
			}
				
			else i++;
		}
		
		
		if(!((*iter)->kind() == SymTabEntry::BLOCK_KIND && i == 1))
			this->symTab()->printST(os,indent,'(',')',false,0,i-1);
		
		else
		{
			os<<"("<<")";
		}		
		os<<"{"<<endl;
		if((*iter)->symTab() != NULL)
		(*iter)->symTab()->printST(os,indent,'\0','\0');
		
		this->body()->printWithoutBraces(os,indent);
		os<<"}";
	}
	os<<";";
}

void FunctionEntry::typePrint(ostream& os, int indent) const{

	//Ying
	//this->print(os,0);
	if(this->type()){
		if(this->type()->retType())
			os<<this->type()->retType()->name()<<" ";
		os<<this->name()<<" ";

		//const vector<const Type*>* args ;
		//args = this->type()->argTypes();
                if (this->body_!= NULL)
                    this->symTab()->typePrintST(os,0,'(',')',false,0,999);


		os<<";";
	}

}
/****************************************************************/
